#include<iostream>
#include <string>
#include <sstream>
#include <typeinfo>
#include <memory>
#include <variant>
#include <cstddef>


using namespace std;

class Ireprable{
public:
    virtual string __repr__() const =0;
};

template<typename TOS>
TOS& operator<<(TOS& os, const Ireprable& a)
{
    return os<< (&a)->__repr__();
}


namespace lisp{
namespace impl{
class atom;
class cons;
class box;
using pointer = std::shared_ptr<box>;
const pointer nil = nullptr;

/* 原子即不可分之物，可以是int，double，string，nullptr */
class atom : public Ireprable{
public:
    atom(int value) : _content(value) {}
    atom(double value) : _content(value) {}
    atom(const char* name) : _content(std::string(name)) {}
    atom(std::string name) : _content(std::move(name)) {}

    virtual std::string __repr__() const 
    {
        if(_content.index()==0) {
            return to_string(std::get<0>(_content));
        } else if(_content.index()==1) {
            return to_string(std::get<1>(_content));
        } else if(_content.index()==2) {
            return std::move(std::get<2>(_content));
        }
        cerr<<"error atom type"<<endl;
        exit(1);
    }
private:
    std::variant<int, double, std::string> _content;
};

//一个cons就是两个指针，指针必指向一个box,box里要么是一个atom要么是一个cons。
class cons: public Ireprable{
    pointer p_head;
    pointer p_tail;
public:
    cons(pointer h, pointer t): p_head(h), p_tail(t) {};

    virtual string __repr__() const; 
};

class box: public Ireprable {
    std::variant<atom, cons> _content;
public:
    box(int     i):_content(atom(i)){}
    box(double  d):_content(atom(d)){}
    box(string  s):_content(atom(s)){}
    box(cons&   c):_content(make_shared<cons>(c)){}
    int index() {return _content.index();}
    virtual string __repr__() const;
};

string cons::__repr__() const {
        std::stringstream ss;
        ss<<"(cons "<<p_head->__repr__();
        if(p_tail->index()==0){
            ss<<" . "<<p_tail->__repr__();
        } else {
            ss<<" "<<p_tail->__repr__();
        }
        ss<<")";
        return ss.str();
}

/**/
string box::__repr__() const {

    return 
//        nil == this?
//            string("()"):
            (_content.index()==0?
                (&std::get<0>(_content))->__repr__():
                (std::get<1>(_content)==nullptr?
                    string("()"):
                    std::get<1>(_content)->__repr__()))
            ;
}
}//lisp::impl::




template<class T1, class T2>
auto cons(T1 o1, T2 o2) {
    return  make_shared<pair<T1, T2>>(o1, o2);
}

template<class T1, class T2>
auto car(shared_ptr<std::pair<T1, T2>> p_cons) {
    return p_cons-
}
}//lisp::

int main()
{
    using lisp::impl::atom;
    using lisp::impl::nil;
    atom i(1111);
    atom d(1.1);
    atom s("fdfs");
    atom(1);
    atom(1.1);
    atom("abc");
    cout<<i<<' '<<d<<' '<<s<<endl;
    cout<<atom(1234)<<' '<<atom(1.2345)<<' '<<atom("abcde")<<endl;
    
    using lisp::impl::box;
    cout<<"box test:"<<endl
        <<box("box test")<<endl
        <<box(22222222)<<endl
        <<box(2.222222)<<endl
        <<box(nullptr)<<endl;
    
    using lisp::cons;


 //   cout<<cons(1, 1.23)<<endl;
 //   cout<<cons(2, "abc")<<endl;
 //   cout<<cons(3, cons(1.23, cons("abc", 0)))<<endl;
 //   cout<<cons(4,nil)<<endl;
#if(0)
    cout<<
        cons(cons(1, 
                  cons(1.11, 
                       cons("abc", nil))), 
             cons(2.22, 
                  cons("abc", nil)))
        <<endl;
#endif
    cout<<endl<<"THE END"<<endl;
}

